import { injectStyle } from "@/utils/dom"
import { onUnmounted } from "vue"

interface IInjectStyle {
    dom: HTMLElement[]
    prop: any
    value?: string
}

const toPx = (s: string | number): number => {
    if (typeof s === "number") return s
    let unit = String(/^a-zA-Z/g.exec(s))?.toLocaleLowerCase()
    if (!unit) return Number(s)
    let num = Number(/\D/g.exec(s))
    let result: any
    if (unit === "vw") {
        result = (document.documentElement.clientWidth / 100) * num
    } else if (unit === "vh") {
        result = (document.documentElement.clientHeight / 100) * num
    } else if (unit === "px") {
        result = num
    }
    return result
}

export declare interface IFlexLayoutOptions {
    column?: number // 列数
    row?: number // 行数

    elBoxWidth?: number // 元素盒子宽度
    elBoxHeight?: number // 元素盒子高度

    elWidthGap?: number
    elHeightGap?: number

    margin?: number
    marginExact?: number[]

    padding?: number
    paddingExact?: number[]

    isResize?: boolean // 是否自适应
    resizeTime?: number // 自适应时间间隔
    resizeOptions?: {
        breakpoint?: number // 自适应断点
        row?: number // 自适应行数
        column?: number // 自适应列数
    }[] // 自适应配置
}
// 初始化布局
const init = (el: HTMLElement, options: IFlexLayoutOptions) => {
    if (el.children.length <= 0) return
    const children = Array.from(el.children);
    injectStyle(el, {
        display: "flex",
        flexWrap: "wrap",
        ' align-items': 'center',
        'justify-content': 'space-around'
    })

    const EL_COUNT = children.length
    const IS_ROW = !!options.row
    const IS_COLUMN = !!options.column
    const IS_ROW_AND_COLUMN = IS_ROW === false && IS_COLUMN === false;

    // 元素父盒子宽高
    let elBoxWidth = !!options.elBoxWidth ? toPx(options.elBoxWidth) : el.clientWidth
    let elBoxHeight = !!options.elBoxHeight ? toPx(options.elBoxHeight) : el.clientHeight

    // 定义元素宽高 和 行列
    let elWidth: number, elHeight: number;

    // 如果行列都没设置
    if (IS_ROW_AND_COLUMN) {
        injectStyle(children, 'flex', '1');
        return;
    }

    // 如果设置了列
    if (IS_COLUMN) {
        elWidth = elBoxWidth / options.column - options.elWidthGap;
    }

    // 如果设置了行
    if (IS_ROW) {
        elHeight = elBoxHeight / options.row - options.elHeightGap;
    }

    elWidth = elWidth ? elWidth : elBoxWidth;
    elHeight = elHeight ? elHeight : elBoxHeight;

    let margin = `${options.marginExact[0]}px ${options.marginExact[1]}px ${options.marginExact[2]}px ${options.marginExact[3]}px`;
    let padding = `${options.paddingExact[0]}px ${options.paddingExact[1]}px ${options.paddingExact[2]}px ${options.paddingExact[3]}px`;

    options.margin && (margin = `${options.margin}px`);
    options.padding && (padding = `${options.padding}px`);

    children.forEach((el: HTMLElement, index: number, arr: Array<HTMLElement>) => {
        if (options.row * options.column > index) {
            // 剩余的个数
            const REMAIN_EL_COUNT = EL_COUNT % options.column
            if (index === EL_COUNT - 1 && REMAIN_EL_COUNT) {
                // 剩余宽度的倍数
                const REMAIN_EL_WIDTH_MULTI = options.column / REMAIN_EL_COUNT
                injectStyle(children.slice(EL_COUNT - REMAIN_EL_COUNT), {
                    width: elWidth * REMAIN_EL_WIDTH_MULTI + "px",
                    height: elHeight + 'px',
                    display: "inline-flex",
                    padding: padding || '',
                    margin: margin || ''
                })
            }
            injectStyle(el, {
                width: elWidth + "px",
                height: elHeight + 'px',
                display: "inline-flex",
                padding: padding || '',
                margin: margin || ''
            })
        } else {
            injectStyle(el, "display", "none")
        }
    })
}
let rawOptions: IFlexLayoutOptions

// resize布局
const resize = (options: IFlexLayoutOptions) => {
    // 判断是否存在resizeOptions
    if (options.resizeOptions.length) {
        // 提取所有断点，并从小到大排序
        const BREAKPOINTS = options.resizeOptions.map(item => item.breakpoint).sort((a, b) => a - b)
        // 如果当前视口宽度大于最大断点，则返回原配置
        if (document.documentElement.clientWidth > BREAKPOINTS[BREAKPOINTS.length - 1]) return rawOptions

        // 当前视口宽度与断点逐个比较，如果当前视口宽度小于断点就返回当前断点
        const CURRENT_BREAKPOINT = BREAKPOINTS.filter(breakpoint => document.documentElement.clientWidth < breakpoint)[0]
        // 根据断点找到对应的配置
        const CURRENT_OPTIONS = options.resizeOptions.find(item => item.breakpoint === CURRENT_BREAKPOINT)
        // 合并配置
        options = Object.assign({}, options, CURRENT_OPTIONS)
    }
    // 返回合并后的配置
    return options
}

let timer: any

export default function initFlexLayout(elSelector: string | HTMLElement, options: IFlexLayoutOptions = {}) {
    rawOptions = options
    const defaultOptions: IFlexLayoutOptions = {
        row: 0,
        column: 0,
        elBoxWidth: undefined,
        elBoxHeight: undefined,
        elWidthGap: 0,
        elHeightGap: 0,
        margin: 0,
        marginExact: [0, 0, 0, 0],
        padding: 0,
        paddingExact: [0, 0, 0, 0],
        isResize: false,
        resizeTime: 100,
        resizeOptions: []
    }
    let el = elSelector as HTMLElement;
    if (typeof elSelector === 'string') {
        el = document.querySelector(elSelector.trim())
    }
    if (!el) return;
    // 合并默认配置
    options = Object.assign({}, defaultOptions, options)

    if (options.isResize) {
        options = resize(options)
    }
    const resizeHandler = () => {
        clearTimeout(timer)
        // console.log("resize");
        timer = setTimeout(() => init(el, options), options.resizeTime)
    }
    window.addEventListener("resize", resizeHandler, { capture: true })
    window.dispatchEvent(new Event("resize"))
    onUnmounted(() => {
        window.removeEventListener("resize", resizeHandler, { capture: true })
    })
}
